{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "# 字典,用于建立用户于物品的索引\n",
    "from collections import defaultdict\n",
    "\n",
    "#稀疏矩阵，　存储打分表\n",
    "import scipy.io as sio\n",
    "\n",
    "#数据到文件存储\n",
    "import pickle\n",
    "\n",
    "import os\n",
    "\n",
    "# 距离\n",
    "import scipy.spatial.distance as ssd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "624\n",
      "800\n"
     ]
    }
   ],
   "source": [
    "# 用户和item的索引\n",
    "\n",
    "users_index = pickle.load(open(\"user_index.pkl\", 'rb'))\n",
    "items_index = pickle.load(open(\"items_index.pkl\", 'rb'))\n",
    "\n",
    "n_users = len(users_index)\n",
    "n_items = len(items_index)\n",
    "print(n_users)\n",
    "print(n_items)\n",
    "\n",
    "# 倒排表\n",
    "user_items = pickle.load(open(\"user_items.pkl\", 'rb'))\n",
    "item_users = pickle.load(open(\"item_users.pkl\", 'rb'))\n",
    "\n",
    "user_item_scores = sio.mmread(\"user_item_scores\")\n",
    "user_item_scores = user_item_scores.tocsr()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 计算每个用户的平均打分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.02995604904\n",
      "0.126453488372\n",
      "0.0789473684211\n",
      "0.0373746581586\n",
      "0.0128339995792\n",
      "0.0321930214278\n",
      "0.0416070732024\n",
      "0.0139331878462\n",
      "0.0486661277284\n",
      "0.00629133731247\n",
      "0.0157507276151\n",
      "0.0185428146593\n",
      "0.0817162570073\n",
      "0.00996486075418\n",
      "0.0202917523845\n",
      "0.0154414963027\n",
      "0.00939875604699\n",
      "0.0680473372781\n",
      "0.00495509445649\n",
      "0.0230163196398\n",
      "0.0810905277875\n",
      "0.16197519084\n",
      "0.0352237182103\n",
      "0.0321428571429\n",
      "0.00675428988682\n",
      "0.0203661797984\n",
      "0.0248291849683\n",
      "0.0112141769348\n",
      "0.0809313468593\n",
      "0.0140870471305\n",
      "0.126597131682\n",
      "0.00875770353552\n",
      "0.00607631856113\n",
      "0.0112371350557\n",
      "0.0508545227178\n",
      "0.00747638143139\n",
      "0.105678233438\n",
      "0.0100731629732\n",
      "0.0112532845881\n",
      "0.0372383252818\n",
      "0.03599514435\n",
      "0.0157096424702\n",
      "0.0148395075004\n",
      "0.00434836625668\n",
      "0.0236220472441\n",
      "0.0694495078381\n",
      "0.00969348151233\n",
      "0.0299260440437\n",
      "0.134409667195\n",
      "0.0274574245593\n",
      "0.0518049398353\n",
      "0.0181760076699\n",
      "0.0549637835535\n",
      "0.013249430812\n",
      "0.0177521890368\n",
      "0.0212695577387\n",
      "0.02086916638\n",
      "0.252427184466\n",
      "0.647609659931\n",
      "0.0192499807884\n",
      "0.0296446700508\n",
      "0.0158027812895\n",
      "0.0825472704768\n",
      "0.00909575728846\n",
      "0.0117899249732\n",
      "0.00529130632681\n",
      "0.0206255701409\n",
      "0.00619699934768\n",
      "0.0106935052681\n",
      "0.00263157894737\n",
      "0.0194827671463\n",
      "0.00462550836955\n",
      "0.0169188020994\n",
      "0.37528604119\n",
      "0.039951328331\n",
      "0.0337237194864\n",
      "0.00982984415342\n",
      "0.0102829586554\n",
      "0.00946655422867\n",
      "0.0910923014913\n",
      "0.0381516197994\n",
      "0.0316036433895\n",
      "0.0267506033653\n",
      "0.0778892886448\n",
      "0.0350032815576\n",
      "0.103086290153\n",
      "0.0209605448567\n",
      "0.010147043116\n",
      "0.034980282997\n",
      "0.0340166369578\n",
      "0.0143312101911\n",
      "0.0377169559413\n",
      "0.0166297117517\n",
      "0.0142906336088\n",
      "0.0367545076283\n",
      "0.0290419161677\n",
      "0.0047619047619\n",
      "0.00396480030945\n",
      "0.00742115027829\n",
      "0.0153720640646\n",
      "0.0566694514063\n",
      "0.0384263494968\n",
      "0.138176638177\n",
      "0.0242891486363\n",
      "0.0159217478224\n",
      "0.00502318392581\n",
      "0.00820267131243\n",
      "0.0707048212894\n",
      "0.0244145490782\n",
      "0.00743396226415\n",
      "0.0102805474701\n",
      "0.00673290981159\n",
      "0.017335866931\n",
      "0.537974683544\n",
      "0.043856062155\n",
      "0.00376368613139\n",
      "0.109483960948\n",
      "0.464019851117\n",
      "0.0195578231293\n",
      "0.232258064516\n",
      "0.0106829104044\n",
      "0.00505263157895\n",
      "0.0051724137931\n",
      "0.0161090458488\n",
      "0.00917182078745\n",
      "0.458695652174\n",
      "0.00656814449918\n",
      "0.014935787429\n",
      "0.11702559935\n",
      "0.169475655431\n",
      "0.0437691664343\n",
      "0.0240879670491\n",
      "0.100810185185\n",
      "0.0412111831286\n",
      "0.0558755760369\n",
      "0.0403737070404\n",
      "0.00559552358114\n",
      "0.120015048909\n",
      "0.0339491204092\n",
      "0.0189175575083\n",
      "0.0155516431925\n",
      "0.0536480686695\n",
      "0.00535459699612\n",
      "0.0433099225644\n",
      "0.13\n",
      "0.00845163178692\n",
      "0.00502680965147\n",
      "0.00533734065706\n",
      "0.096301691349\n",
      "0.020183708001\n",
      "0.160074888837\n",
      "0.655193607867\n",
      "0.0877480057271\n",
      "0.0263558033452\n",
      "0.0286888683835\n",
      "0.00641025641026\n",
      "0.0273180076628\n",
      "0.0142403947832\n",
      "0.0248235157968\n",
      "0.0152030048292\n",
      "0.0447008547009\n",
      "0.0908211521926\n",
      "0.0984496124031\n",
      "0.00431750249087\n",
      "0.0162007623888\n",
      "0.029197080292\n",
      "0.00766541975839\n",
      "0.0617254528122\n",
      "0.0198686107996\n",
      "0.0457076566125\n",
      "0.0388261851016\n",
      "0.0168634064081\n",
      "0.158846754201\n",
      "0.176059769368\n",
      "0.0365749929118\n",
      "0.0240151106314\n",
      "0.105920444033\n",
      "0.0483664690152\n",
      "0.0230921649599\n",
      "0.0143195157177\n",
      "0.0391779680036\n",
      "0.0231630479126\n",
      "0.0128291488059\n",
      "0.0203566274995\n",
      "0.00561066840137\n",
      "0.0311895702077\n",
      "0.174640217814\n",
      "0.0174126376257\n",
      "0.00602018277102\n",
      "0.0112719677326\n",
      "0.0227526210127\n",
      "0.0440981432361\n",
      "0.041105275177\n",
      "0.0332946186605\n",
      "0.0120247568523\n",
      "0.00930440839885\n",
      "0.0405215764238\n",
      "0.0175971122688\n",
      "0.0123529029322\n",
      "0.0596298834818\n",
      "0.0408015800376\n",
      "0.0211990464369\n",
      "0.051234404035\n",
      "0.211743119266\n",
      "0.0916083916084\n",
      "0.336126629423\n",
      "0.0291643580315\n",
      "0.0120894071914\n",
      "0.00793365583967\n",
      "0.0050571564031\n",
      "0.0237641008626\n",
      "0.0244522070499\n",
      "0.00536672629696\n",
      "0.022257446668\n",
      "0.0142171549046\n",
      "0.0173796791444\n",
      "0.0228059611621\n",
      "0.00561734319426\n",
      "0.00457366873571\n",
      "0.0330989330747\n",
      "0.0644292013719\n",
      "0.087982832618\n",
      "0.0850315506362\n",
      "0.00844959717037\n",
      "0.0184175033718\n",
      "0.0985774893936\n",
      "0.299591836735\n",
      "0.182057785071\n",
      "0.0183400393001\n",
      "0.00622711601678\n",
      "0.0430488731324\n",
      "0.00431355049829\n",
      "0.0586548114155\n",
      "0.0738510937186\n",
      "0.0760555234239\n",
      "0.0561180214058\n",
      "0.0145197319434\n",
      "0.00807565614706\n",
      "0.0101404406156\n",
      "0.0143806435665\n",
      "0.0400320657348\n",
      "0.00537793566213\n",
      "0.00651637900669\n",
      "0.256540513081\n",
      "0.148384673178\n",
      "0.109369898792\n",
      "0.0073420292119\n",
      "0.607476635514\n",
      "0.00518184899995\n",
      "0.0290685772774\n",
      "0.0244360902256\n",
      "0.00661390406123\n",
      "0.00507614213198\n",
      "0.103777112939\n",
      "0.0140281297051\n",
      "0.0321428571429\n",
      "0.0224243572737\n",
      "0.024582459692\n",
      "0.00884552252417\n",
      "0.0155364266219\n",
      "0.0266853932584\n",
      "0.0170720382871\n",
      "0.010775862069\n",
      "0.013155751059\n",
      "0.0201219512195\n",
      "0.0510018214936\n",
      "0.032062125173\n",
      "0.0225115868462\n",
      "0.0673226307613\n",
      "0.00824355207313\n",
      "0.0171476102118\n",
      "0.00929677439618\n",
      "0.0226907630522\n",
      "0.0511873350923\n",
      "0.00167224080268\n",
      "0.0465928945836\n",
      "0.0180981595092\n",
      "0.0336616381997\n",
      "0.0316640077686\n",
      "0.0231430805317\n",
      "0.0287057658995\n",
      "0.0218733291207\n",
      "0.0219279809444\n",
      "0.065113455263\n",
      "0.0918712001801\n",
      "0.0140266423206\n",
      "0.00937672366244\n",
      "0.015181720595\n",
      "0.0360687305584\n",
      "0.00594442652412\n",
      "0.00755532943271\n",
      "0.0141545218607\n",
      "0.0617589925648\n",
      "0.0171428571429\n",
      "0.121317829457\n",
      "0.00871156909935\n",
      "0.0424242424242\n",
      "0.0126319798565\n",
      "0.00600961538462\n",
      "0.00984574991795\n",
      "0.077056514197\n",
      "0.00876494023904\n",
      "0.026890538674\n",
      "0.0138944025407\n",
      "0.0110923105847\n",
      "0.0112865932516\n",
      "2.1696969697\n",
      "0.0586267605634\n",
      "0.013611784449\n",
      "0.00906270696086\n",
      "0.00688477344292\n",
      "0.00916271721959\n",
      "0.0197757570407\n",
      "0.0186358279316\n",
      "0.196078431373\n",
      "0.0222555802115\n",
      "0.0673665791776\n",
      "0.0148112372213\n",
      "0.0419154150694\n",
      "0.0349943799176\n",
      "0.008869955942\n",
      "0.0226768310335\n",
      "0.0756793945648\n",
      "0.0159680638723\n",
      "0.103585902002\n",
      "0.0288964069062\n",
      "0.00895956468712\n",
      "0.028549382716\n",
      "0.0159726183685\n",
      "0.018596112311\n",
      "0.0229693314513\n",
      "0.0075548548154\n",
      "0.0147834688943\n",
      "0.00711475970583\n",
      "0.0651332270553\n",
      "0.0549973084515\n",
      "0.0484096049276\n",
      "0.0140086698608\n",
      "0.017191563132\n",
      "0.0145380271537\n",
      "0.384615384615\n",
      "0.0271606657845\n",
      "0.011901504788\n",
      "0.291725601132\n",
      "0.0440633818103\n",
      "0.0130395097144\n",
      "0.024407688869\n",
      "0.0113228389948\n",
      "0.0319634703196\n",
      "0.0479682854311\n",
      "0.0287948367879\n",
      "0.415384615385\n",
      "0.00770620108368\n",
      "0.00493577168892\n",
      "0.0179858944443\n",
      "0.0082349944817\n",
      "0.0431302597878\n",
      "0.11652835408\n",
      "0.0116655313351\n",
      "0.0217801838096\n",
      "0.0121828094501\n",
      "0.0841628154995\n",
      "0.0144398051496\n",
      "0.17878528657\n",
      "0.0173725771716\n",
      "0.00736165699669\n",
      "0.00723779444664\n",
      "0.0473491599534\n",
      "0.0432432432432\n",
      "0.0545992001391\n",
      "0.0125028941885\n",
      "0.00512589928058\n",
      "0.0155520995334\n",
      "0.00996741422273\n",
      "0.0128816793893\n",
      "0.0761990138951\n",
      "0.0356012185652\n",
      "0.0611186903138\n",
      "0.0145698427382\n",
      "0.0811193765498\n",
      "0.345991561181\n",
      "0.016148294304\n",
      "0.142132516115\n",
      "0.0175794455713\n",
      "0.115133768135\n",
      "0.0511988716502\n",
      "0.367200818275\n",
      "0.00642527273944\n",
      "0.0146131805158\n",
      "0.0325845160886\n",
      "0.0201361431541\n",
      "0.00681189721454\n",
      "0.0254076086957\n",
      "0.0124782007337\n",
      "1.0280857354\n",
      "0.076287524098\n",
      "0.0280140070035\n",
      "0.0764462809917\n",
      "0.1\n",
      "0.00615909249078\n",
      "0.0213277836817\n",
      "0.0393920595533\n",
      "0.0364116869769\n",
      "0.0482173539519\n",
      "0.136983026536\n",
      "0.223541048467\n",
      "0.0241137675185\n",
      "0.0219741583897\n",
      "0.0204020700637\n",
      "0.0453166093466\n",
      "0.00918301521648\n",
      "0.0612565445026\n",
      "0.00924564407292\n",
      "0.0110233083206\n",
      "0.0405674615152\n",
      "0.0226288340847\n",
      "0.0368007850834\n",
      "0.0115502417063\n",
      "0.0469798657718\n",
      "0.0171390120329\n",
      "0.0230839760531\n",
      "0.00789998188078\n",
      "0.0351546344378\n",
      "0.0157367668097\n",
      "0.00972035292358\n",
      "0.0277869665895\n",
      "0.654796094199\n",
      "0.00845720143516\n",
      "0.00997666010709\n",
      "0.0322910578609\n",
      "0.0329657483537\n",
      "0.0111207242187\n",
      "0.00645387891294\n",
      "0.02\n",
      "0.0857740585774\n",
      "0.170561909498\n",
      "0.00853540252182\n",
      "0.00878023586124\n",
      "0.0218208935867\n",
      "0.0125012602077\n",
      "0.0587449933244\n",
      "0.0241904018728\n",
      "0.0152027027027\n",
      "0.00793825314452\n",
      "0.0157359699206\n",
      "0.209891080365\n",
      "0.0228379397847\n",
      "0.00842891901286\n",
      "0.0292056074766\n",
      "0.0144679793004\n",
      "0.0404518950437\n",
      "0.238656663094\n",
      "0.0539086016601\n",
      "0.0461176470588\n",
      "0.0219811427922\n",
      "0.0064151911727\n",
      "0.11252900232\n",
      "0.0116723884257\n",
      "0.126315789474\n",
      "0.13452124535\n",
      "0.0723277149563\n",
      "0.0110018955308\n",
      "0.0456505818211\n",
      "0.00690763859235\n",
      "0.0459561602419\n",
      "0.0357507660878\n",
      "0.0181068178658\n",
      "0.0536603356076\n",
      "0.0151187904968\n",
      "0.0109831234932\n",
      "0.0478260869565\n",
      "0.0123321150698\n",
      "0.00570349246324\n",
      "0.0150483697599\n",
      "0.0265148222203\n",
      "0.370265914585\n",
      "0.00614253096523\n",
      "0.0419206061604\n",
      "0.0203105717812\n",
      "0.0195289206917\n",
      "0.0117737773955\n",
      "0.0119495728028\n",
      "0.133646322379\n",
      "0.00779467680608\n",
      "0.0243834471228\n",
      "0.0149029630221\n",
      "0.0127205199629\n",
      "0.0124161468754\n",
      "0.02502596054\n",
      "0.00851300479124\n",
      "0.0804020100503\n",
      "0.00419869057785\n",
      "0.0211068842803\n",
      "0.0055487053021\n",
      "0.0192653224196\n",
      "0.0303597421501\n",
      "0.254578282177\n",
      "0.00979354155638\n",
      "0.0286316814016\n",
      "0.0229952830189\n",
      "0.0176029647098\n",
      "0.0106825749168\n",
      "0.036496350365\n",
      "0.00958596225189\n",
      "0.0105156894086\n",
      "0.0167306540805\n",
      "0.0221269129545\n",
      "0.0219814241486\n",
      "0.028004748935\n",
      "0.0675246826516\n",
      "0.0229616243223\n",
      "0.013500448864\n",
      "0.0302607482341\n",
      "0.0419322850262\n",
      "0.0322355984479\n",
      "0.489768076398\n",
      "0.0271448092477\n",
      "0.0500840739851\n",
      "0.00424345295829\n",
      "0.0229844413013\n",
      "0.0242325074022\n",
      "0.0240756663801\n",
      "0.0344885038321\n",
      "0.0201638311279\n",
      "0.0458216581507\n",
      "0.10770474473\n",
      "0.0183176669077\n",
      "0.139812889813\n",
      "0.115078345749\n",
      "0.0213631739573\n",
      "0.0115779645191\n",
      "0.0396173630539\n",
      "0.00982079578819\n",
      "0.0420067210754\n",
      "0.00696517412935\n",
      "0.0438074174889\n",
      "0.0659314022543\n",
      "0.0115174695947\n",
      "0.0524310118265\n",
      "0.0701270016565\n",
      "0.00449101796407\n",
      "0.0393092940579\n",
      "0.019191732792\n",
      "0.129043600563\n",
      "0.022453145296\n",
      "0.0155089014113\n",
      "0.0289702087732\n",
      "0.0616651133893\n",
      "0.083977158213\n",
      "0.060207739682\n",
      "0.100169779287\n",
      "0.0491621877964\n",
      "0.00941704035874\n",
      "0.118961352657\n",
      "0.0146621334467\n",
      "0.079703174385\n",
      "0.0169512195122\n",
      "0.0528970208773\n",
      "0.0506271724346\n",
      "0.113461538462\n",
      "0.0248184675409\n",
      "0.022190093035\n",
      "0.0091706539075\n",
      "0.041204437401\n",
      "0.0160186884699\n",
      "0.0121557926073\n",
      "0.0429197994987\n",
      "0.0143995098039\n",
      "0.0114249843063\n",
      "0.0433526011561\n",
      "0.0184902666748\n",
      "0.0321342399649\n",
      "0.0461773034197\n",
      "0.0171936056838\n",
      "0.102819237148\n",
      "0.0116909233444\n",
      "0.0156469906449\n",
      "0.0798177522781\n",
      "0.00962131068958\n",
      "0.00877489031387\n",
      "0.0337103088299\n",
      "0.0332379023811\n",
      "0.00459242250287\n",
      "0.0105392587388\n",
      "0.0120034295513\n",
      "0.0322735799144\n",
      "0.0224503610108\n",
      "0.00417353102691\n",
      "0.00632297606579\n",
      "0.0117209154985\n",
      "0.0253077975376\n",
      "0.0259030418251\n",
      "0.0386487260235\n",
      "0.0126057986674\n",
      "0.0155547669742\n",
      "0.0117038419133\n",
      "0.0367817223891\n",
      "0.0447667804323\n",
      "0.0181494661922\n",
      "0.0148272305312\n",
      "0.0177304964539\n",
      "0.0153980105436\n",
      "0.017749274861\n",
      "0.0370634354954\n",
      "0.0724025974026\n",
      "0.0408830744072\n",
      "0.0205710280122\n",
      "0.0771706833939\n",
      "0.0083850593488\n",
      "0.0245981967856\n",
      "0.00621234939759\n",
      "0.0191021210488\n",
      "0.0120160546456\n",
      "0.00463160660907\n",
      "0.011700138713\n",
      "0.105755246208\n",
      "0.0388489208633\n",
      "0.00647619047619\n",
      "0.0243947514323\n",
      "0.0282060066233\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.00890349757467\n",
      "0.054756436601\n",
      "0.0875309661437\n",
      "0.0627674750357\n"
     ]
    }
   ],
   "source": [
    "users_mu = np.zeros(n_users)\n",
    "\n",
    "for u in range(n_users):\n",
    "    n_user_items = 0\n",
    "    r_acc = 0.0\n",
    "    \n",
    "    for i in user_items[u]:\n",
    "        r_acc += user_item_scores[u, i]\n",
    "        n_user_items += i\n",
    "    \n",
    "    users_mu[u] = r_acc/n_user_items\n",
    "    print(users_mu[u])\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 计算两个用户之间的相似度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def user_similarity(uid1, uid2):\n",
    "    si={} # 有效的item(两个用具均有打分的集合)\n",
    "    for item in user_items[uid1]:\n",
    "        if item in user_items[uid2]:\n",
    "            si[item] = 1  # 用户1点打分过用户2也打分,则item为一个有效的item\n",
    "    \n",
    "    n = len(si)\n",
    "    \n",
    "    if n==0 :\n",
    "        similarity = 0.0\n",
    "        return similarity\n",
    "    \n",
    "    #用户uid1的有效打分(减去该用户的平均打分)\n",
    "    s1=np.array([user_item_scores[uid1,item]-users_mu[uid1] for item in si])  \n",
    "        \n",
    "    #用户uid2的有效打分(减去该用户的平均打分)\n",
    "    s2=np.array([user_item_scores[uid2,item]-users_mu[uid2] for item in si])  \n",
    "        \n",
    "    # ssd.cosine(s1, s2) 算的是两个向量的距离\n",
    "    similarity = 1 - ssd.cosine(s1, s2) \n",
    "    \n",
    "    if np.isnan(similarity): #s1或s2的l2模为0（全部等于该用户的平均打分）\n",
    "        similarity = 0.0\n",
    "    return similarity  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 预计算好所有用户之间的相似性\n",
    "- 对用户比较少、用户比较固定的的系统适用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ui=0 \n",
      "ui=100 \n",
      "ui=200 \n",
      "ui=300 \n",
      "ui=400 \n",
      "ui=500 \n",
      "ui=600 \n"
     ]
    }
   ],
   "source": [
    "users_similarity_matrix = np.matrix(np.zeros(shape=(n_users, n_users)), float)\n",
    "\n",
    "for ui in range(n_users):\n",
    "    users_similarity_matrix[ui,ui] = 1.0 # 自己对自己的相似度为1\n",
    "    \n",
    "    #打印进度条\n",
    "    if(ui % 100 == 0):\n",
    "        print (\"ui=%d \" % (ui))\n",
    "\n",
    "    for uj in range(ui+1,n_users):   \n",
    "        users_similarity_matrix[uj,ui] = user_similarity(ui, uj)\n",
    "        users_similarity_matrix[ui,uj] = users_similarity_matrix[uj,ui] # 做成对称\n",
    "\n",
    "pickle.dump(users_similarity_matrix, open(\"users_similarity.pkl\", 'wb')) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def users_similarity(n_users ):\n",
    "    users_similarity_matrix = np.matrix(np.zeros(shape=(n_users, n_users)), float)\n",
    "\n",
    "    for ui in range(n_users):\n",
    "        users_similarity_matrix[ui,ui] = 1.0\n",
    "    \n",
    "        #打印进度条\n",
    "        if(ui % 100 == 0):\n",
    "            print (\"ui=:%d \" % (ui))\n",
    "\n",
    "        for uj in range(ui+1,n_users):   \n",
    "            users_similarity_matrix[uj,ui] = user_similarity(ui, uj)\n",
    "            users_similarity_matrix[ui,uj] = users_similarity_matrix[uj,ui]\n",
    "\n",
    "    cPickle.dump(users_similarity_matrix, open(\"users_similarity.pkl\", 'wb')) \n",
    "    return users_similarity_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 测试\n",
    "## 预测用户对item的打分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "### 预测用户对item的打分\n",
    "def User_CF_pred(uid, iid): \n",
    "    sim_accumulate=0.0  # 相似度绝对值的和\n",
    "    rat_acc=0.0 #相似度加权打分的和\n",
    "    for user_id in item_users[iid]:  #对item iid打过分的所有用户\n",
    "        #计算当前用户与给item i打过分的用户之间的相似度\n",
    "        sim = users_similarity_matrix[user_id,uid]\n",
    "        \n",
    "        # 若为新用户可以直接计算得到\n",
    "        # sim = user_similarity(user_id, uid)\n",
    "            \n",
    "        if sim != 0: \n",
    "            rat_acc += sim * (user_item_scores[user_id,iid] - users_mu[user_id])   #用户user对item i的打分\n",
    "            sim_accumulate += np.abs(sim)  \n",
    "        \n",
    "    if sim_accumulate != 0:  \n",
    "        score = users_mu[uid] + rat_acc/sim_accumulate\n",
    "    else: #no similar users,return average rates of the user \n",
    "        score = users_mu[uid]\n",
    "    \n",
    "    return score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 对给定用户，推荐物品/计算打分\n",
    "- 不同的推荐算法，只是预测打分函数不同，\n",
    "- user_items_scores[i] = User_CF_pred(cur_user_id, i)  #预测打分\n",
    "\n",
    "- 如User_CF_pred, Item_CF_pred, svd_CF_pred,...\n",
    "- 甚至基于内容的推荐也是一样。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "0\n",
      "User_CF_pred: 10.210043256\n"
     ]
    }
   ],
   "source": [
    "cur_user_id = users_index['4e11f45d732f4861772b2906f81a7d384552ad12']\n",
    "print(cur_user_id)\n",
    "\n",
    "cur_item_id = items_index['SOCKSGZ12A58A7CA4B']\n",
    "print(cur_item_id)\n",
    "\n",
    "#cur_user_items = user_items[cur_user_id]\n",
    "#print('cur_user_items:', cur_user_items)\n",
    "#print('n_items:', n_items)\n",
    "\n",
    "print('User_CF_pred:', User_CF_pred(cur_user_id, 0))  #预测打分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#user：用户\n",
    "#返回推荐items及其打分（DataFrame）\n",
    "def recommend(user):\n",
    "    cur_user_id = users_index[user]\n",
    "    \n",
    "    \n",
    "    #训练集中该用户打过分的item\n",
    "    cur_user_items = user_items[cur_user_id]\n",
    "\n",
    "    #该用户对所有item的打分\n",
    "    user_items_scores = np.zeros(n_items)\n",
    "\n",
    "    #预测打分\n",
    "    for i in range(n_items):  # all items \n",
    "        if i not in cur_user_items: #训练集中没打过分\n",
    "            user_items_scores[i] = User_CF_pred(cur_user_id, i)  #预测打分\n",
    "    \n",
    "    #推荐\n",
    "    #Sort the indices of user_item_scores based upon their value，Also maintain the corresponding score\n",
    "    sort_index = sorted(((e,i) for i,e in enumerate(list(user_items_scores))), reverse=True)\n",
    "    \n",
    "    #Create a dataframe from the following\n",
    "    columns = ['song', 'score']\n",
    "    df = pd.DataFrame(columns=columns)\n",
    "         \n",
    "    #Fill the dataframe with top 20 (n_rec_items) item based recommendations\n",
    "    #sort_index = sort_index[0:n_rec_items]\n",
    "    #Fill the dataframe with all items based recommendations\n",
    "    for i in range(0,len(sort_index)):\n",
    "        cur_item_index = sort_index[i][1] \n",
    "        cur_item = list (items_index.keys()) [list (items_index.values()).index (cur_item_index)]\n",
    "            \n",
    "        if ~np.isnan(sort_index[i][0]) and cur_item_index not in cur_user_items:\n",
    "            df.loc[len(df)]=[cur_item, sort_index[i][0]]\n",
    "    \n",
    "    return df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>song</th>\n",
       "      <th>score</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>SOBONKR12A58A7A7E0</td>\n",
       "      <td>60.750024</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>SOZOWON12A67ADA091</td>\n",
       "      <td>46.161335</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>SOTLHUV12A6D4FC541</td>\n",
       "      <td>45.885355</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>SOIPYPB12A8C1360D4</td>\n",
       "      <td>39.228591</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>SOMLYJD12A58A7B155</td>\n",
       "      <td>38.924642</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>SOWUTFF12A8C138AB2</td>\n",
       "      <td>35.202698</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>SOYGQGR12AF72ABAB8</td>\n",
       "      <td>34.617349</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>SOITRTA12A6D4F8261</td>\n",
       "      <td>33.384340</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>SOVHKJL12AB017E2B2</td>\n",
       "      <td>33.099740</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>SOYVFTH12A67020868</td>\n",
       "      <td>31.349135</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>SOXCCPU12A58A7BF1E</td>\n",
       "      <td>29.826493</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>SORWLJM12A6D4F9C0C</td>\n",
       "      <td>29.581844</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>SOPTPWD12A6D4FBD4E</td>\n",
       "      <td>28.972160</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>SOLGPOU12A58A7EA20</td>\n",
       "      <td>28.898640</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>SOSXLTC12AF72A7F54</td>\n",
       "      <td>28.197954</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>SOVTQLS12A6D4F8350</td>\n",
       "      <td>27.777405</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>SOIZFTE12AB0186842</td>\n",
       "      <td>27.395608</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>SOXFYTY127E9433E7D</td>\n",
       "      <td>25.475813</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>SOOLYZQ12A6D4FA5B7</td>\n",
       "      <td>25.404525</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>SOUWEJS12AB01868A4</td>\n",
       "      <td>25.237900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>SOPREHY12AB01815F9</td>\n",
       "      <td>24.489066</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>SOUDLVN12AAFF43658</td>\n",
       "      <td>22.978174</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>SOZEBAZ12AF72A80C8</td>\n",
       "      <td>22.100168</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>SOQQAAQ12A67ADE34D</td>\n",
       "      <td>21.542247</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>SOPUCYA12A8C13A694</td>\n",
       "      <td>21.298639</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>SOOFYTN12A6D4F9B35</td>\n",
       "      <td>21.255644</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>SOXEYIE12AB0180212</td>\n",
       "      <td>21.250366</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>SONIQRE12AF72A2B02</td>\n",
       "      <td>21.218508</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>SOBOUPA12A6D4F81F1</td>\n",
       "      <td>20.959161</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>SOQBMFK12A8C13835B</td>\n",
       "      <td>20.909579</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>638</th>\n",
       "      <td>SOVHPUT12A81C22A56</td>\n",
       "      <td>2.501675</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>639</th>\n",
       "      <td>SOYPRBR12A8C14396C</td>\n",
       "      <td>2.461996</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>640</th>\n",
       "      <td>SOYHTAT12A81C23955</td>\n",
       "      <td>2.436784</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>641</th>\n",
       "      <td>SOXILLO12A6310F1B6</td>\n",
       "      <td>2.431622</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>642</th>\n",
       "      <td>SOUCMUI12AB018C0C6</td>\n",
       "      <td>2.428000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>643</th>\n",
       "      <td>SOWNIUS12A8C142815</td>\n",
       "      <td>2.416645</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>644</th>\n",
       "      <td>SOXFMAQ12A6D4F91E0</td>\n",
       "      <td>2.414462</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>645</th>\n",
       "      <td>SOZVMYF12A8C132646</td>\n",
       "      <td>2.378272</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>646</th>\n",
       "      <td>SOWBYZF12A6D4F9424</td>\n",
       "      <td>2.370330</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>647</th>\n",
       "      <td>SOMWTWK12AB01860CD</td>\n",
       "      <td>2.318082</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>648</th>\n",
       "      <td>SOXDPEP12AB0180E1E</td>\n",
       "      <td>2.299379</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>649</th>\n",
       "      <td>SOYJPNY12AB01869CC</td>\n",
       "      <td>2.296472</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>650</th>\n",
       "      <td>SOXPSGF12AB0187589</td>\n",
       "      <td>2.289496</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>651</th>\n",
       "      <td>SOQCNFV12A6701D92A</td>\n",
       "      <td>2.273268</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>652</th>\n",
       "      <td>SOZXKIA12A6D4F861C</td>\n",
       "      <td>2.251121</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>653</th>\n",
       "      <td>SOUEGBF12AB017EFD5</td>\n",
       "      <td>2.237175</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>654</th>\n",
       "      <td>SOXGIWN12A6310E0D8</td>\n",
       "      <td>2.201569</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>655</th>\n",
       "      <td>SOXTBGF12A6D4FB49C</td>\n",
       "      <td>2.153408</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>656</th>\n",
       "      <td>SOSUZFA12A8C13C04A</td>\n",
       "      <td>2.129736</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>657</th>\n",
       "      <td>SOWQJUV12A6701FA45</td>\n",
       "      <td>2.078714</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>658</th>\n",
       "      <td>SOXJHPY12AF72A5227</td>\n",
       "      <td>2.072609</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>659</th>\n",
       "      <td>SOZJHUF12A8C13E642</td>\n",
       "      <td>2.028000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>660</th>\n",
       "      <td>SOZEETS12AC9071BD3</td>\n",
       "      <td>1.834139</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>661</th>\n",
       "      <td>SOUBZPQ12A8C13629D</td>\n",
       "      <td>1.803845</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>662</th>\n",
       "      <td>SOXTTHY12A8C137072</td>\n",
       "      <td>1.778337</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>663</th>\n",
       "      <td>SOWEBRA12A6701F115</td>\n",
       "      <td>1.770608</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>664</th>\n",
       "      <td>SOUXNNU12A67020A48</td>\n",
       "      <td>1.711382</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>665</th>\n",
       "      <td>SOSXSMM12B0B808B45</td>\n",
       "      <td>1.665849</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>666</th>\n",
       "      <td>SOSXVAS12A6310F1AD</td>\n",
       "      <td>1.343685</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>667</th>\n",
       "      <td>SOYUDDS12A6D4F7BD6</td>\n",
       "      <td>1.294103</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>668 rows × 2 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                   song      score\n",
       "0    SOBONKR12A58A7A7E0  60.750024\n",
       "1    SOZOWON12A67ADA091  46.161335\n",
       "2    SOTLHUV12A6D4FC541  45.885355\n",
       "3    SOIPYPB12A8C1360D4  39.228591\n",
       "4    SOMLYJD12A58A7B155  38.924642\n",
       "5    SOWUTFF12A8C138AB2  35.202698\n",
       "6    SOYGQGR12AF72ABAB8  34.617349\n",
       "7    SOITRTA12A6D4F8261  33.384340\n",
       "8    SOVHKJL12AB017E2B2  33.099740\n",
       "9    SOYVFTH12A67020868  31.349135\n",
       "10   SOXCCPU12A58A7BF1E  29.826493\n",
       "11   SORWLJM12A6D4F9C0C  29.581844\n",
       "12   SOPTPWD12A6D4FBD4E  28.972160\n",
       "13   SOLGPOU12A58A7EA20  28.898640\n",
       "14   SOSXLTC12AF72A7F54  28.197954\n",
       "15   SOVTQLS12A6D4F8350  27.777405\n",
       "16   SOIZFTE12AB0186842  27.395608\n",
       "17   SOXFYTY127E9433E7D  25.475813\n",
       "18   SOOLYZQ12A6D4FA5B7  25.404525\n",
       "19   SOUWEJS12AB01868A4  25.237900\n",
       "20   SOPREHY12AB01815F9  24.489066\n",
       "21   SOUDLVN12AAFF43658  22.978174\n",
       "22   SOZEBAZ12AF72A80C8  22.100168\n",
       "23   SOQQAAQ12A67ADE34D  21.542247\n",
       "24   SOPUCYA12A8C13A694  21.298639\n",
       "25   SOOFYTN12A6D4F9B35  21.255644\n",
       "26   SOXEYIE12AB0180212  21.250366\n",
       "27   SONIQRE12AF72A2B02  21.218508\n",
       "28   SOBOUPA12A6D4F81F1  20.959161\n",
       "29   SOQBMFK12A8C13835B  20.909579\n",
       "..                  ...        ...\n",
       "638  SOVHPUT12A81C22A56   2.501675\n",
       "639  SOYPRBR12A8C14396C   2.461996\n",
       "640  SOYHTAT12A81C23955   2.436784\n",
       "641  SOXILLO12A6310F1B6   2.431622\n",
       "642  SOUCMUI12AB018C0C6   2.428000\n",
       "643  SOWNIUS12A8C142815   2.416645\n",
       "644  SOXFMAQ12A6D4F91E0   2.414462\n",
       "645  SOZVMYF12A8C132646   2.378272\n",
       "646  SOWBYZF12A6D4F9424   2.370330\n",
       "647  SOMWTWK12AB01860CD   2.318082\n",
       "648  SOXDPEP12AB0180E1E   2.299379\n",
       "649  SOYJPNY12AB01869CC   2.296472\n",
       "650  SOXPSGF12AB0187589   2.289496\n",
       "651  SOQCNFV12A6701D92A   2.273268\n",
       "652  SOZXKIA12A6D4F861C   2.251121\n",
       "653  SOUEGBF12AB017EFD5   2.237175\n",
       "654  SOXGIWN12A6310E0D8   2.201569\n",
       "655  SOXTBGF12A6D4FB49C   2.153408\n",
       "656  SOSUZFA12A8C13C04A   2.129736\n",
       "657  SOWQJUV12A6701FA45   2.078714\n",
       "658  SOXJHPY12AF72A5227   2.072609\n",
       "659  SOZJHUF12A8C13E642   2.028000\n",
       "660  SOZEETS12AC9071BD3   1.834139\n",
       "661  SOUBZPQ12A8C13629D   1.803845\n",
       "662  SOXTTHY12A8C137072   1.778337\n",
       "663  SOWEBRA12A6701F115   1.770608\n",
       "664  SOUXNNU12A67020A48   1.711382\n",
       "665  SOSXSMM12B0B808B45   1.665849\n",
       "666  SOSXVAS12A6310F1AD   1.343685\n",
       "667  SOYUDDS12A6D4F7BD6   1.294103\n",
       "\n",
       "[668 rows x 2 columns]"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "recommend('4e11f45d732f4861772b2906f81a7d384552ad12')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 读取测试数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user</th>\n",
       "      <th>song</th>\n",
       "      <th>play_count</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>484734ce6667a6a25df23a961d5c5a9458afbfa1</td>\n",
       "      <td>SOWDLPO12A6D4F72BB</td>\n",
       "      <td>30</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>484734ce6667a6a25df23a961d5c5a9458afbfa1</td>\n",
       "      <td>SOWIMTL12A8C1386DC</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>484734ce6667a6a25df23a961d5c5a9458afbfa1</td>\n",
       "      <td>SOWKRSR12A8C13CA37</td>\n",
       "      <td>19</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>484734ce6667a6a25df23a961d5c5a9458afbfa1</td>\n",
       "      <td>SOXFYTY127E9433E7D</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>484734ce6667a6a25df23a961d5c5a9458afbfa1</td>\n",
       "      <td>SOXKOIY12A8C13C1EA</td>\n",
       "      <td>9</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                       user                song  play_count\n",
       "0  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOWDLPO12A6D4F72BB          30\n",
       "1  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOWIMTL12A8C1386DC           3\n",
       "2  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOWKRSR12A8C13CA37          19\n",
       "3  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOXFYTY127E9433E7D           1\n",
       "4  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOXKOIY12A8C13C1EA           9"
      ]
     },
     "execution_count": 111,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#读取测试数据\n",
    "dpath = './data/'\n",
    "df_triplet_test = pd.read_csv(dpath +'test.csv')\n",
    "\n",
    "df_triplet_test.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 测试，并计算评价指标\n",
    "PR、覆盖度、RMSE\n",
    "这部分代码所有的推荐算法相同\n",
    "\n",
    "令系统的用户集合为 U， R(u) 是根据用户在训练集上的行为给用户作出的推荐列表，而 T(u) 是用户在测试集上的行为列表。那么推荐结果的准确率定义为：\n",
    "$$\n",
    "Precision=\\frac{\\sum_{u\\in U}|R(u)\\cap T(u)|}{\\sum_{u\\in U}|R(u)|}\n",
    "$$\n",
    "推荐结果的召回率定义为：\n",
    "$$\n",
    "Recall=\\frac{\\sum_{u\\in U}|R(u)\\cap T(u)|}{\\sum_{u\\in U}|T(u)|}\n",
    "$$\n",
    "\n",
    "推荐系统的覆盖率为：\n",
    "$$\n",
    "Coverage=\\frac{\\sum_{u\\in U}|R(u)|}{|I|}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 测试代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#性能评价参数初始化，用户计算Percison和Recall\n",
    "n_hits = 0 # 击中数\n",
    "n_total_rec_items = 0 # 总共推荐多少商品\n",
    "n_test_items = 0 # 测试集里出现了多少商品\n",
    "n_rec_items = 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def printUserIndex(user):\n",
    "    print('User_Index:')\n",
    "    for u in users_index:\n",
    "        print(user[u])\n",
    "        \n",
    "def printItemIndex(item):\n",
    "    print('Item_Index:')\n",
    "    for i in items_index:\n",
    "        print(user[i])      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {},
   "outputs": [],
   "source": [
    "def test(user):\n",
    "    global n_hits\n",
    "    global n_total_rec_items\n",
    "    global n_test_items\n",
    "    #测试集中该用户打过分的电影（用于计算评价指标的真实值）\n",
    "    if user not in users_index:   #user在训练集中没有出现过，新用户不能用协同过滤\n",
    "        print(str(user) + ' is a new user.\\n')\n",
    "        return\n",
    "\n",
    "    # 找出此用户的记录\n",
    "    user_records_test= df_triplet_test[df_triplet_test.user == user]\n",
    "    #print(user_records_test)\n",
    "\n",
    "    #对每个测试用户，计算该用户对训练集中未出现过的商品的打分，并基于该打分进行推荐（top n_rec_items）\n",
    "    #返回结果为DataFrame\n",
    "    rec_items = recommend(user)\n",
    "    rec_items = rec_items.iloc[0: n_rec_items]\n",
    "    \n",
    "    #print('rec_items:', rec_items)\n",
    "    printItemIndex(rec_items)\n",
    "    \n",
    "    #print('user_records_test:', user_records_test['song'].values)\n",
    "    #print(\"test==:\", rec_items.iloc[0])\n",
    "    print(user_records_test['song'])\n",
    "    for i in range(n_rec_items):\n",
    "        item = rec_items.iloc[i]['song']\n",
    "        print('item:', item)\n",
    "        # 若推荐的歌曲在真是的用户数据中出现过,则hit+1\n",
    "        if item in user_records_test['song'].values:\n",
    "            n_hits += 1\n",
    "        all_rec_items.add(item)\n",
    "\n",
    "    print('n_hits:', n_hits)\n",
    "    print('all_rec_items:', all_rec_items)\n",
    "\n",
    "    \n",
    "    '''\n",
    "    #计算rmse\n",
    "    for i in range(user_records_test.shape[0]):\n",
    "        item = user_records_test.iloc[i]['song']\n",
    "        score = user_records_test.iloc[i]['play_count']\n",
    "        print('item:', item)\n",
    "        print('rec_items.song:', rec_items.song)\n",
    "        print('items_index[item]:', items_index[item])\n",
    "        df1 = rec_items[rec_items.song == item]\n",
    "        if(df1.shape[0] == 0): #item在训练集中没有出现过，新item不能被协同过滤推荐\n",
    "            print(str(item) + ' is a new item.\\n')\n",
    "            continue\n",
    "        pred_score = df1['score'].values[0]\n",
    "        rss_test += (pred_score - score)**2     #残差平方和\n",
    "    '''\n",
    "    #推荐的item总数\n",
    "    n_total_rec_items += n_rec_items\n",
    "\n",
    "    #真实item的总数\n",
    "    n_test_items += user_records_test.shape[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rec_items:                  song      score\n",
      "0  SOBONKR12A58A7A7E0  60.750024\n",
      "1  SOZOWON12A67ADA091  46.161335\n",
      "2  SOTLHUV12A6D4FC541  45.885355\n",
      "3  SOIPYPB12A8C1360D4  39.228591\n",
      "4  SOMLYJD12A58A7B155  38.924642\n",
      "5  SOWUTFF12A8C138AB2  35.202698\n",
      "6  SOYGQGR12AF72ABAB8  34.617349\n",
      "7  SOITRTA12A6D4F8261  33.384340\n",
      "8  SOVHKJL12AB017E2B2  33.099740\n",
      "9  SOYVFTH12A67020868  31.349135\n",
      "0    SOCKSGZ12A58A7CA4B\n",
      "1    SOCVTLJ12A6310F0FD\n",
      "2    SODLLYS12A8C13A96B\n",
      "3    SOEGIYH12A6D4FC0E3\n",
      "4    SOFRQTD12A81C233C0\n",
      "5    SOHEMBB12A6701E907\n",
      "6    SOHJOLH12A6310DFE5\n",
      "7    SOIZLKI12A6D4F7B61\n",
      "8    SOJGSIO12A8C141DBF\n",
      "9    SOKEYJQ12A6D4F6132\n",
      "Name: song, dtype: object\n",
      "item: SOBONKR12A58A7A7E0\n",
      "item: SOZOWON12A67ADA091\n",
      "item: SOTLHUV12A6D4FC541\n",
      "item: SOIPYPB12A8C1360D4\n",
      "item: SOMLYJD12A58A7B155\n",
      "item: SOWUTFF12A8C138AB2\n",
      "item: SOYGQGR12AF72ABAB8\n",
      "item: SOITRTA12A6D4F8261\n",
      "item: SOVHKJL12AB017E2B2\n",
      "item: SOYVFTH12A67020868\n",
      "n_hits: 0\n",
      "all_rec_items: {'SOITRTA12A6D4F8261', 'SOTLHUV12A6D4FC541', 'SOYGQGR12AF72ABAB8', 'SOMLYJD12A58A7B155', 'SOYVFTH12A67020868', 'SOBONKR12A58A7A7E0', 'SOWUTFF12A8C138AB2', 'SOIPYPB12A8C1360D4', 'SOVHKJL12AB017E2B2', 'SOZOWON12A67ADA091'}\n"
     ]
    }
   ],
   "source": [
    "test('4e11f45d732f4861772b2906f81a7d384552ad12')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 测试，并计算评价指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                                       user                song  play_count\n",
      "0  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOWDLPO12A6D4F72BB          30\n",
      "1  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOWIMTL12A8C1386DC           3\n",
      "2  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOWKRSR12A8C13CA37          19\n",
      "3  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOXFYTY127E9433E7D           1\n",
      "4  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOXKOIY12A8C13C1EA           9\n",
      "5  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOYKFFK12A8C14391D          38\n",
      "6  484734ce6667a6a25df23a961d5c5a9458afbfa1  SOYNJCS12A67ADE35F           8\n",
      "92d2e8ff105b7b7ddc163e740921cafdbcd815bf is a new user.\n",
      "\n",
      "15b447e75c02e91a9d8ce92fd6f2d1366d07d380 is a new user.\n",
      "\n",
      "6b9ef666e3b10fd428530e519e1a3f68c2fbbd1a is a new user.\n",
      "\n",
      "9784566a61c79b18b5d72584f3cc95ea134d14de is a new user.\n",
      "\n",
      "45d34f6b12ce922136ea7c6a82de3524be24d683 is a new user.\n",
      "\n",
      "7e80a4beb851feae1f2c16a2779f0e9ff424647a is a new user.\n",
      "\n",
      "5588ce55d35d7c70f06e1928ec0967117c5d712b is a new user.\n",
      "\n",
      "6a6d346cc92ee699a765a06fd97db74b864a8129 is a new user.\n",
      "\n",
      "bd3478df2f64daf2e38b0550c988157b2c118481 is a new user.\n",
      "\n",
      "4748dd6561d01b44a5add4c9e1e4282f1578bdcc is a new user.\n",
      "\n",
      "7560076aa3ff4c9a46d917262a87a3d830543469 is a new user.\n",
      "\n",
      "b7c24f770be6b802805ac0e2106624a517643c17 is a new user.\n",
      "\n",
      "92227472de1d2ed14725adff31cfa56a3f29047b is a new user.\n",
      "\n",
      "4f9827b79319210f9e35259bce0587cf04f74a03 is a new user.\n",
      "\n",
      "168db3745c3e7255a1ef0e759fa4e413e5ba9dfc is a new user.\n",
      "\n",
      "8b64bf1db75f427e41133d39955fb3f1a28417d9 is a new user.\n",
      "\n",
      "1fc2a7f42424249718cc544a0a1036a69d5bc7b8 is a new user.\n",
      "\n",
      "7323c1c0cc06f5f77f61db323d00a0a628092848 is a new user.\n",
      "\n",
      "6babcd5c5d0d794480580eab45820e489c344a0f is a new user.\n",
      "\n",
      "87b9680d2db44f901bf79d9a61fb298dbb2a6603 is a new user.\n",
      "\n",
      "e851e806941435c6d5748bd64c1c55e5c0551ab1 is a new user.\n",
      "\n",
      "e6b18cffa2afad9245b7d9eb08390efeebef1f3b is a new user.\n",
      "\n",
      "1991ec49e285545363025ffcb4988c6dd860c766 is a new user.\n",
      "\n",
      "480f3a551bbcdb53f8eb28e44614aa7ce0cc8d0e is a new user.\n",
      "\n",
      "44bf2bb66daf59a20d7b7df64fda29ec16c74cb9 is a new user.\n",
      "\n",
      "59565a9a2a86c12c54bd887c723a47c7f8ab8090 is a new user.\n",
      "\n",
      "6c8faa430c61308b863c22f322ea9fef161f1be8 is a new user.\n",
      "\n",
      "dbb235f944fe78ef8198950e64e4bbc2bdbef172 is a new user.\n",
      "\n",
      "83b94f1d1bf5581499cc0738807c8c41f3bf6706 is a new user.\n",
      "\n",
      "52a6c7b6221f57c89dacbbd06854ca0dc415e9e6 is a new user.\n",
      "\n",
      "e46932327dfffa6ec69dbadbe9dd883a3a383673 is a new user.\n",
      "\n",
      "93743199681d206189b5288a3cb421970e4cd872 is a new user.\n",
      "\n",
      "c405c586f6d7aadbbadfcba5393b543fd99372ff is a new user.\n",
      "\n",
      "33db1f9a79d6400c01112f2b4897eeee533b1b8b is a new user.\n",
      "\n",
      "9254a3fdc569428c3b1c3904db36d485c47e2544 is a new user.\n",
      "\n",
      "e8184db22c453007c34ba8ab7e2a4cda8ca7969b is a new user.\n",
      "\n",
      "421a43936c80f2232747bdcf340e2744fdf37aa6 is a new user.\n",
      "\n",
      "fe67eae6791418a5a85125145609f518f01efe48 is a new user.\n",
      "\n",
      "145f15885973e477a91d2fc560a63850622e0d9e is a new user.\n",
      "\n",
      "90d2fcb1dbe47dc1e9442587e259811a0437a13f is a new user.\n",
      "\n",
      "02471b044e6bdff7c01e1ea2791214268ba5aaf4 is a new user.\n",
      "\n",
      "4626aa787c5e156440970cc12f9ecad4cde3f06b is a new user.\n",
      "\n",
      "0d54fad06b250c41865f6af5b8d35dd5c5750c75 is a new user.\n",
      "\n",
      "a403e8052c47447959193e549dc6b609e6724466 is a new user.\n",
      "\n",
      "627fae8384469c99391b504f9d98030999019e85 is a new user.\n",
      "\n",
      "c2dbf6f4c32dc36af4d6fadb16cd8b79c64a6aa8 is a new user.\n",
      "\n",
      "a18aa09c5b8a1c03d03cdf6d8eb11c2bf5b907cd is a new user.\n",
      "\n",
      "16a169fe2aae8b9def552092527db97a412bee7d is a new user.\n",
      "\n",
      "80f3cceeac5a7266b6d3696c04f21925e72bf9f4 is a new user.\n",
      "\n",
      "41d990857d4659738215aadddb0d6e630685d278 is a new user.\n",
      "\n",
      "aff2b00aeba4a389d22c474dc33645e0a6dfd56e is a new user.\n",
      "\n",
      "18d857219b6fedae682aa3a5e2be18ec526ab241 is a new user.\n",
      "\n",
      "eb75703cc9f9a33c4b1d2f7b3abf9a6be4c732aa is a new user.\n",
      "\n",
      "6b36f65d2eb5579a8b9ed5b4731a7e13b8760722 is a new user.\n",
      "\n",
      "839223f11c98e0c8017e8ecd6fc7b8706658c966 is a new user.\n",
      "\n",
      "22e08d5e101ab5b86dc394856d508e175a5242a6 is a new user.\n",
      "\n",
      "974a05be3d2385f40af4e6e610be59544657085e is a new user.\n",
      "\n",
      "bf82fdc9210bdaa712a5e310a35fe9784d5700e4 is a new user.\n",
      "\n",
      "83522e9d56c3cda41d1853465f1b05f4c2d07550 is a new user.\n",
      "\n",
      "5b68b39d7c8d66935839aa58121abd46605b34cc is a new user.\n",
      "\n",
      "5fb2630c42e4a08f4f5456306d547a1de3c60100 is a new user.\n",
      "\n",
      "68bfa6f926e2b47eefe4ca41a2b1eb7b4d4fc001 is a new user.\n",
      "\n",
      "c7417a59a6d67ef869bf970671b5246c4e3e16d6 is a new user.\n",
      "\n",
      "6eb4c037657215db0d6f4d37bec84fb491374df9 is a new user.\n",
      "\n",
      "074a2197ff72db9f7e44606dfd33208dcdf29f06 is a new user.\n",
      "\n",
      "66abc1ae25dca07b75109164f9dacfe33f9572ba is a new user.\n",
      "\n",
      "3ab78e39bddeaeb789edad041fff03050077417c is a new user.\n",
      "\n",
      "13a2d690b099bcd3fdd256bd39aa14edadd5db08 is a new user.\n",
      "\n",
      "fb644c3f2a83114325dc67b97df0bce60b5ac9a1 is a new user.\n",
      "\n",
      "33e3fc88b0ab07f872bf7515413887374dd76ad6 is a new user.\n",
      "\n",
      "a4a068221b97aad518af038628daf1180e30113a is a new user.\n",
      "\n",
      "37e0e4c4cb5b1e6022908bd129f70c70e08ac68b is a new user.\n",
      "\n",
      "6a3657565b45f103af50ec87321e36712f098aba is a new user.\n",
      "\n",
      "acedfad21e1fd702aacda8111551f00b1f6f378e is a new user.\n",
      "\n",
      "956dc1095d8f22575d3936191ce20b789b0ffc4d is a new user.\n",
      "\n",
      "716ed1ec67d67bfa05db3ffeb641d13f46dca6ec is a new user.\n",
      "\n",
      "2401e90ee6a2796f74cf01c5e808ae8a0540ad61 is a new user.\n",
      "\n",
      "22f6aae94643c2cea285413068f80274e7f1f75e is a new user.\n",
      "\n",
      "7893479225de4c7d4646e90c9bf15f9f624e2cff is a new user.\n",
      "\n",
      "18765abd13462c176d9ccc89e71bfc23265dfed7 is a new user.\n",
      "\n",
      "36bee226881241a38e3c9997cf0c84e2959035e7 is a new user.\n",
      "\n",
      "7be76db45f21dcbb68ff9cc55ebeddcb1db71479 is a new user.\n",
      "\n",
      "148163a8a9c6173a11fb36c3215c1a19251e63c8 is a new user.\n",
      "\n",
      "4d744903c553122fb4815d06e047aba9f974b938 is a new user.\n",
      "\n",
      "752d48df8a89c534e9957d85209837c6a943a14f is a new user.\n",
      "\n",
      "1280b7963657a12b28a8ca58bf736ddeb256fda1 is a new user.\n",
      "\n",
      "49c8369971513c689d0ca6d0382e5c5a710df7e7 is a new user.\n",
      "\n",
      "aec9f74039a6d861551c5e4e0a799a2ec4196c81 is a new user.\n",
      "\n",
      "a05e548059abb1f77cad6cb9c3c0c48e0616f551 is a new user.\n",
      "\n",
      "e7775d30ad499fa204257d1246a7f87a6bfcc80f is a new user.\n",
      "\n",
      "e82b3380f770c78f8f067f464941057c798eaca2 is a new user.\n",
      "\n",
      "dd3696048c81b1aff836a606cda7e14be5bb92a6 is a new user.\n",
      "\n",
      "4cb4632e48cd8960dc113eae340adc402a0413cf is a new user.\n",
      "\n",
      "a4ccc36714975978b545e35db83584fa9f7fa6c6 is a new user.\n",
      "\n",
      "998e2858f6ffb758e298ad2223da4b7a65e676e3 is a new user.\n",
      "\n",
      "f9edc8907be695518817082a224aa43beca7d994 is a new user.\n",
      "\n",
      "bd82eefb8f1ddc894b48ee2baca28c89ff70710d is a new user.\n",
      "\n",
      "3907d4fe152c83b3aeaa28b294f23daf072eca46 is a new user.\n",
      "\n",
      "3996245591e28d4ab3fc572cae1c44c456e2fa34 is a new user.\n",
      "\n",
      "f9cf7849592621b46a793e0f283de8ab48b3d5f8 is a new user.\n",
      "\n",
      "99dedd05d478e3aa54b199f4432fcb9907456b34 is a new user.\n",
      "\n",
      "754f985cb55753e84f1933f3280b06e2bb379847 is a new user.\n",
      "\n",
      "6d147ffb9f1b7d7188cdb964dd15093227818421 is a new user.\n",
      "\n",
      "91008efedbdb903424a51e3cd18b8b80624dd4f4 is a new user.\n",
      "\n",
      "c0dc381d5ddf02f5182179c164ca65db6c8f572b is a new user.\n",
      "\n",
      "4cbca37009400bb5676ba54c2a4cc24ff0531cb7 is a new user.\n",
      "\n",
      "8084aef08dffb1c0323bc6af17f80b3cd9e2e7f3 is a new user.\n",
      "\n",
      "3a11e6d1f8aa60342e2486922edf199deadb2026 is a new user.\n",
      "\n",
      "dfd62f3ee786c4579b262421b33b8110d931733f is a new user.\n",
      "\n",
      "fa5d9eddc010bc3fc71f8a42db15e5dd4f1c18a3 is a new user.\n",
      "\n",
      "174b880b7340e2921b281493cfc6337bb7d99579 is a new user.\n",
      "\n",
      "6c99ae7e53e91f7e839444b2f00c8503a4a10fcf is a new user.\n",
      "\n",
      "d0a2c5ac5ce1bc3573224d910fe3adfb85d4ee3f is a new user.\n",
      "\n",
      "eb69f5a5465388b63fe66a410f7c58e17fb7bade is a new user.\n",
      "\n",
      "c802248ec0f960549720bb9f409fec7264b8b2f9 is a new user.\n",
      "\n",
      "954469357b2434a20c76e940eca93185141b7f9b is a new user.\n",
      "\n",
      "6270f977ebf8da9f90e2ff2d23bc570fa012b5ee is a new user.\n",
      "\n",
      "9bf0c40652e96b5178b552d2b296ec69b75a0b26 is a new user.\n",
      "\n",
      "c5d0030d32982330235e80d3395e412c38c552d1 is a new user.\n",
      "\n",
      "3fa44653315697f42410a30cb766a4eb102080bb is a new user.\n",
      "\n",
      "40e46bab2caa78cfe7150218f53ab7aed69a7b1e is a new user.\n",
      "\n",
      "91fc617d2632f554f364015e6e7fb10f3eacce1f is a new user.\n",
      "\n",
      "0fb08af6e4cd85e39f0c939097792a95be3431ee is a new user.\n",
      "\n",
      "339fbf843dcf3f7ec3a7f43c37b6a1ff37f5b817 is a new user.\n",
      "\n",
      "b82d692dde839cfe9fd6d309bb8c46d50089cc16 is a new user.\n",
      "\n",
      "2b8b819c92836d86d891d2c41bd25fdffd759898 is a new user.\n",
      "\n",
      "97e2a28f577accc9efa329a9f78f151994f917b4 is a new user.\n",
      "\n",
      "2744a71984cdf296fb94de2b9d5aa0f065ffb1ab is a new user.\n",
      "\n",
      "f986a1b01b2a75109baa39d637537b5124c111ab is a new user.\n",
      "\n",
      "2c04736f4d7b0696d2a063b1e61069af38660a94 is a new user.\n",
      "\n",
      "dc543ff951c23be4e9e8fdf6f39a23cef85f3b5e is a new user.\n",
      "\n",
      "d375c4189987e1029e61b35aff6d34d568e6705c is a new user.\n",
      "\n",
      "8ec7fd0c1acf1dbe44720e5eab44dbe524eb6caf is a new user.\n",
      "\n",
      "d71adb94c30db90d20b08bde62acb7ef1966083d is a new user.\n",
      "\n",
      "ec06a94669597cdc8d1360c6a906aa95333326e8 is a new user.\n",
      "\n",
      "2668af52749df405c6eee58d41c8afd434f617e2 is a new user.\n",
      "\n",
      "aabbd8b9388076451e70846a86cd4c8cb426873f is a new user.\n",
      "\n",
      "4d98756ff69be79de228c15432245766d4bf0316 is a new user.\n",
      "\n",
      "00fa0c8162aa95341f4da9defede8aae0675d3cc is a new user.\n",
      "\n",
      "fbd1b7d1bf19158773820cb45639362347979926 is a new user.\n",
      "\n",
      "3877e44d4632df125ec8a838aae59eb04d36f9d6 is a new user.\n",
      "\n",
      "d7d2d888ae04d16e994d6964214a1de81392ee04 is a new user.\n",
      "\n",
      "53456e59daa8f3a8498880dbebf595ae02be9de9 is a new user.\n",
      "\n",
      "146ad3a976414133d661a070b20f62edfc958d52 is a new user.\n",
      "\n",
      "168afb3dd9c92b4724171543c1c123aa26dd4cd1 is a new user.\n",
      "\n",
      "f629b337d01f254e0d685ccc66ec2fd5ddba78d9 is a new user.\n",
      "\n",
      "6e15cb4dcfdda600d893d230fb7aba1d9d0ff218 is a new user.\n",
      "\n",
      "60a90b3801bb9599b85a8448c6d44589fd1f984d is a new user.\n",
      "\n",
      "6a49ecaa3727df93615074768fe683491d274377 is a new user.\n",
      "\n",
      "33a1286454a3cff06e3c2324be746d2e23d7c270 is a new user.\n",
      "\n",
      "f02ef1e670319151d2d27f4215fb16a973f7de2f is a new user.\n",
      "\n",
      "7e543508a213f4f22e0cb54ecf2df9c370070a28 is a new user.\n",
      "\n",
      "6c6289326f70321f2b3e072daa44819efc55639a is a new user.\n",
      "\n",
      "53cc3e95468819addbfcaa1256b460984c581be3 is a new user.\n",
      "\n",
      "e6e0f68e948d7bcbf2ed9c4506a40a139a5e7bc7 is a new user.\n",
      "\n",
      "80ae8f21a060a7fdb7b5d4bb3d5f3021e624e19c is a new user.\n",
      "\n",
      "3288389bf9ef956a23a0a4ea86f60bf24ba7f69e is a new user.\n",
      "\n",
      "57f7c9671c77f73db905344afc45627cfe5cba77 is a new user.\n",
      "\n",
      "104bcda48463a99997f668b897c32234793cd514 is a new user.\n",
      "\n",
      "1db9458849024e54f89a807790230aa5701f112d is a new user.\n",
      "\n",
      "73a9b86c602d2ab5eb151b77f58bb6e7315dd7b2 is a new user.\n",
      "\n",
      "35b1d8452b62242a2ded2dc5ea05a0a407023cf7 is a new user.\n",
      "\n",
      "d964fc033291078031d117ed10adfb615948256d is a new user.\n",
      "\n",
      "38ae280090905f0778dd40727f89de3380fb2625 is a new user.\n",
      "\n",
      "1854daf178674bbac9a8ed3d481f95b76676b414 is a new user.\n",
      "\n",
      "491d048e26c51fcda0744355bf191d4ccf36f118 is a new user.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#统计总的用户\n",
    "unique_users_test = df_triplet_test['user'].unique()\n",
    "\n",
    "#为每个用户推荐的item的数目\n",
    "n_rec_items = 10\n",
    "\n",
    "#性能评价参数初始化，用户计算Percison和Recall\n",
    "n_hits = 0 # 击中数\n",
    "n_total_rec_items = 0 # 总共推荐多少商品\n",
    "n_test_items = 0 # 测试集里出现了多少商品\n",
    "\n",
    "#所有被推荐商品的集合（对不同用户），用于计算覆盖度\n",
    "all_rec_items = set()\n",
    "\n",
    "#残差平方和，用与计算RMSE\n",
    "rss_test = 0.0\n",
    "\n",
    "#对每个测试用户\n",
    "for user in unique_users_test:\n",
    "    global n_hits\n",
    "    #测试集中该用户打过分的电影（用于计算评价指标的真实值）\n",
    "    if user not in users_index:   #user在训练集中没有出现过，新用户不能用协同过滤\n",
    "        print(str(user) + ' is a new user.\\n')\n",
    "        continue\n",
    "   \n",
    "    # 找出此用户的记录\n",
    "    user_records_test= df_triplet_test[df_triplet_test.user == user]\n",
    "    print(user_records_test)\n",
    "    \n",
    "    #对每个测试用户，计算该用户对训练集中未出现过的商品的打分，并基于该打分进行推荐（top n_rec_items）\n",
    "    #返回结果为DataFrame\n",
    "    rec_items = recommend(user)\n",
    "    \n",
    "    #print(\"test==:\", rec_items.iloc[0])\n",
    "    \n",
    "    for i in range(n_rec_items):\n",
    "        item = rec_items.iloc[i]['song']\n",
    "        \n",
    "        # 若推荐的歌曲在真是的用户数据中出现过,则hit+1\n",
    "        if item in user_records_test['song'].values:\n",
    "            n_hits += 1\n",
    "        all_rec_items.add(item)\n",
    "    \n",
    "    #计算rmse\n",
    "    for i in range(user_records_test.shape[0]):\n",
    "        item = user_records_test.iloc[i]['song']\n",
    "        score = user_records_test.iloc[i]['play_count']\n",
    "        \n",
    "        df1 = rec_items[rec_items.song == item]\n",
    "        if(df1.shape[0] == 0): #item在训练集中没有出现过，新item不能被协同过滤推荐\n",
    "            print(str(item) + ' is a new item.\\n')\n",
    "            continue\n",
    "        pred_score = df1['score'].values[0]\n",
    "        rss_test += (pred_score - score)**2     #残差平方和\n",
    "    \n",
    "    #推荐的item总数\n",
    "    n_total_rec_items += n_rec_items\n",
    "    \n",
    "    #真实item的总数\n",
    "    n_test_items += user_records_test.shape[0]\n",
    "\n",
    "#Precision & Recall\n",
    "precision = n_hits / (1.0*n_total_rec_items)\n",
    "recall = n_hits / (1.0*n_test_items)\n",
    "\n",
    "#覆盖度：推荐商品占总需要推荐商品的比例\n",
    "coverage = len(all_rec_items) / (1.0* n_items)\n",
    "\n",
    "#打分的均方误差\n",
    "rmse=np.sqrt(rss_test / df_triplet_test.shape[0])  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n_hits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.0"
      ]
     },
     "execution_count": 115,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "precision"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.0"
      ]
     },
     "execution_count": 116,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "recall"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.0125"
      ]
     },
     "execution_count": 117,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "coverage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.5526045627795263"
      ]
     },
     "execution_count": 118,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rmse"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
